package com.ruoyi.framework.shiro.realm;

import java.util.HashSet;
import java.util.Set;

import jakarta.annotation.PostConstruct;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.user.*;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.framework.shiro.service.SysLoginService;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.common.utils.spring.SpringUtils; // 👈 引入工具类
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Role;

/**
 * 自定义Realm 处理登录 权限
 *
 * @author ruoyi
 */
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class UserRealm extends AuthorizingRealm {

    private static final Logger log = LoggerFactory.getLogger(UserRealm.class);

    // 移除 @Autowired，改为延迟获取
    private ISysMenuService menuService;
    private ISysRoleService roleService;
    private SysLoginService loginService;

    /**
     * 初始化，延迟获取 Service 实例
     */
    @PostConstruct
    private void initRealm() {
        this.menuService = SpringUtils.getBean(ISysMenuService.class);
        this.roleService = SpringUtils.getBean(ISysRoleService.class);
        this.loginService = SpringUtils.getBean(SysLoginService.class);
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken || token instanceof BearerToken;
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        SysUser user = ShiroUtils.getSysUser();
        Set<String> roles = new HashSet<>();
        Set<String> menus = new HashSet<>();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        if (user.isAdmin()) {
            info.addRole("admin");
            info.addStringPermission("*:*:*");
        } else {
            roles = roleService.selectRoleKeys(user.getUserId());
            menus = menuService.selectPermsByUserId(user.getUserId());
            info.setRoles(roles);
            info.setStringPermissions(menus);
        }
        return info;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        if (token instanceof BearerToken bearerToken) {
            String tokenStr = bearerToken.getToken();
            return new SimpleAuthenticationInfo("user", tokenStr, getName());
        } else if (token instanceof UsernamePasswordToken upToken) {
            String username = upToken.getUsername();
            String password = "";
            if (upToken.getPassword() != null) {
                password = new String(upToken.getPassword());
            }
            SysUser user;
            try {
                user = loginService.login(username, password);
            } catch (CaptchaException e) {
                throw new AuthenticationException(e.getMessage(), e);
            } catch (UserNotExistsException e) {
                throw new UnknownAccountException(e.getMessage(), e);
            } catch (UserPasswordNotMatchException e) {
                throw new IncorrectCredentialsException(e.getMessage(), e);
            } catch (UserPasswordRetryLimitExceedException e) {
                throw new ExcessiveAttemptsException(e.getMessage(), e);
            } catch (UserBlockedException | RoleBlockedException e) {
                throw new LockedAccountException(e.getMessage(), e);
            } catch (Exception e) {
                log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
                throw new AuthenticationException(e.getMessage(), e);
            }
            return new SimpleAuthenticationInfo(user, password, getName());
        }
        throw new IncorrectCredentialsException("无效的令牌");
    }

    /**
     * 清理指定用户授权信息缓存
     */
    public void clearCachedAuthorizationInfo(Object principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
        this.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 清理所有用户授权信息缓存
     */
    public void clearAllCachedAuthorizationInfo() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache != null) {
            for (Object key : cache.keys()) {
                cache.remove(key);
            }
        }
    }
}